﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.ComponentModel;
using System.Diagnostics;
using System.Windows.Forms;
using FlyCapture2Managed;
using FlyCapture2Managed.Gui;


using Emgu.CV;
using Emgu.CV.CvEnum;
using Emgu.CV.Structure;

namespace DualChannelProject
{
    public class PTGreyCameraControl
    {
        public FlyCapture2Managed.Gui.CameraControlDialog m_camCtlDlg;
        public ManagedCameraBase m_camera = null;
        public ManagedImage m_rawImage;
        private ManagedImage m_processedImage;
        public System.Drawing.Bitmap OutImage = null;
        public bool m_grabImages = false;

        public Thread camThread;
        public ManualResetEvent camThreadHandle = new ManualResetEvent(false);

        public delegate void UpdatePicDel(System.Drawing.Bitmap bmp);
        public UpdatePicDel UpdatePic;


        public int NewCount = 0;
        public double LastShutter = 0;
        public double LastGain = 0;
        public bool Invert = false;
        public ReaderWriterLockSlim RWSLock = new ReaderWriterLockSlim();
        public Object Locker = new object();
        public int Width = 0;
        public int Height = 0;
        public System.Drawing.Size ImageSize
        {
            get { return new System.Drawing.Size(Width, Height); }
        }

        public PTGreyCameraControl()
        {
            m_rawImage = new ManagedImage();
            m_processedImage = new ManagedImage();
            m_camCtlDlg = new CameraControlDialog();
        }
        public void SetGPIOPinDirection(uint Pin, uint IO)
        {
            m_camera.SetGPIOPinDirection(Pin, IO);
        }
        public void SetProperty(CameraProperty Cp)
        {
            m_camera.SetProperty(Cp);
        }
        public void SetStrobe(StrobeControl Sc)
        {
            m_camera.SetStrobe(Sc);
        }
        public void SetTriggerMode(TriggerMode TMode)
        {
            m_camera.SetTriggerMode(TMode);
        }

        public void StopCapture()
        {
            camThreadHandle.Reset();
            if (m_grabImages) m_camera.StopCapture();
            m_grabImages = false;
        }
        public void StartCapture()
        {
            if (!m_grabImages) m_camera.StartCapture();
            m_grabImages = true;
            camThreadHandle.Set();
        }


        public void ShowDialog()
        {
            if (m_camCtlDlg.IsVisible())
            {
                m_camCtlDlg.Hide();

            }
            else
            {
                m_camCtlDlg.Show();

            }
        }

        private void CamLoop(object st)
        {
            ManualResetEvent MREcamThread = (ManualResetEvent)st;
            while (true)
            {
                MREcamThread.WaitOne();
                try
                {
                    m_camera.RetrieveBuffer(m_rawImage);
                }
                catch (FC2Exception ex)
                {
                    //Debug.WriteLine("Error: " + ex.Message);
                    continue;
                }
                RWSLock.EnterWriteLock();
                m_rawImage.Convert(PixelFormat.PixelFormatBgr, m_processedImage);

                LastShutter = m_camera.GetProperty(PropertyType.Shutter).absValue;
                LastGain = Math.Pow(10, m_camera.GetProperty(PropertyType.Gain).absValue / 20.0);
                NewCount++;
                //Stopwatch sw = new Stopwatch();sw.Start();
                OutImage = m_processedImage.bitmap;

                if (Invert) OutImage.RotateFlip(System.Drawing.RotateFlipType.RotateNoneFlipXY);

                RWSLock.ExitWriteLock();
                //Console.WriteLine(sw.ElapsedMilliseconds);

                UpdatePic(OutImage);
                
                GC.Collect();
            }
        }
        public void Dispose()
        {
            try
            {
                StopCapture();
                m_camera.Disconnect();
            }
            catch (FC2Exception ex)
            {
                // Nothing to do here
            }
            catch (NullReferenceException ex)
            {
                // Nothing to do here
            }
        }


        private void StartGrabLoop()
        {
            camThread = new Thread(CamLoop);
            camThread.Start(camThreadHandle);
        }

        public float GetFrameRate()
        {
            return m_camera.GetProperty(PropertyType.FrameRate).absValue;
        }
        public float GetShutter()
        {
            return m_camera.GetProperty(PropertyType.Shutter).absValue;
        }
        public float GetGain()
        {
            return m_camera.GetProperty(PropertyType.Gain).absValue;
        }

        public void InitCameraWithGuid(ManagedPGRGuid guidToUse)
        {
            ManagedBusManager busMgr = new ManagedBusManager();
            InterfaceType ifType = busMgr.GetInterfaceTypeFromGuid(guidToUse);

            if (ifType == InterfaceType.GigE)
            {
                m_camera = new ManagedGigECamera();
            }
            else
            {
                m_camera = new ManagedCamera();
            }
            m_camera.Connect(guidToUse);

            m_camCtlDlg.Connect(m_camera);

            CameraInfo camInfo = m_camera.GetCameraInfo();

            // Set embedded timestamp to on
            EmbeddedImageInfo embeddedInfo = m_camera.GetEmbeddedImageInfo();
            embeddedInfo.timestamp.onOff = true;
            embeddedInfo.gain.onOff = true;
            embeddedInfo.shutter.onOff = true;
            m_camera.SetEmbeddedImageInfo(embeddedInfo);

            m_camera.StartCapture();
            m_grabImages = true;
            m_camera.RetrieveBuffer(m_rawImage);
            Height = (int)m_rawImage.rows; Width = (int)m_rawImage.cols;
            m_camera.StopCapture();
            m_grabImages = false;
            StartGrabLoop();
        }
    }
}
